#ifndef CAMERA_H
#define CAMERA_H

#include "../GameObject/GameObject.h"
#include <algorithm>

// Camera follow modes
enum class CameraFollowMode {
    None,           // Camera doesn't follow anything
    Instant,        // Camera instantly follows target
    Smooth,         // Camera smoothly follows target
    Delayed         // Camera follows with delay
};

// Camera class for managing view transformation
class Camera {
public:
    Camera(float screenWidth = 800.0f, float screenHeight = 600.0f);
    ~Camera() = default;

    // Basic camera properties
    void setPosition(float x, float y);
    void translate(float deltaX, float deltaY);
    
    float getX() const { return x_; }
    float getY() const { return y_; }
    
    // Screen dimensions
    float getScreenWidth() const { return screenWidth_; }
    float getScreenHeight() const { return screenHeight_; }
    void setScreenSize(float width, float height);
    
    // World bounds (for limiting camera movement)
    void setWorldBounds(float minX, float minY, float maxX, float maxY);
    bool hasWorldBounds() const { return hasWorldBounds_; }
    
    // Target following
    void setTarget(GameObject* target);
    GameObject* getTarget() const { return target_; }
    void setFollowMode(CameraFollowMode mode) { followMode_ = mode; }
    CameraFollowMode getFollowMode() const { return followMode_; }
    
    // Smooth following parameters
    void setSmoothness(float smoothness) { smoothness_ = smoothness; }
    float getSmoothness() const { return smoothness_; }
    
    // Offset from target (useful for keeping player slightly off-center)
    void setTargetOffset(float offsetX, float offsetY);
    float getTargetOffsetX() const { return targetOffsetX_; }
    float getTargetOffsetY() const { return targetOffsetY_; }
    
    // Dead zone (area where target can move without camera moving)
    void setDeadZone(float width, float height);
    float getDeadZoneWidth() const { return deadZoneWidth_; }
    float getDeadZoneHeight() const { return deadZoneHeight_; }
    bool isDeadZoneEnabled() const { return deadZoneEnabled_; }
    void setDeadZoneEnabled(bool enabled) { deadZoneEnabled_ = enabled; }
    
    // Update camera (call this every frame)
    void update(float deltaTime);
    
    // Transform world coordinates to screen coordinates
    float worldToScreenX(float worldX) const;
    float worldToScreenY(float worldY) const;
    
    // Transform screen coordinates to world coordinates
    float screenToWorldX(float screenX) const;
    float screenToWorldY(float screenY) const;
    
    // Check if a point is visible on screen
    bool isPointVisible(float worldX, float worldY) const;
    
    // Check if a rectangle is visible on screen
    bool isRectVisible(float worldX, float worldY, float width, float height) const;
    
    // Get camera view bounds in world coordinates
    float getViewLeft() const { return x_; }
    float getViewRight() const { return x_ + screenWidth_; }
    float getViewTop() const { return y_; }
    float getViewBottom() const { return y_ + screenHeight_; }
    
    // Camera shake effect
    void shake(float intensity, float duration);
    void setShakeDecay(float decay) { shakeDecay_ = decay; }
    bool isShaking() const { return shakeTimer_ > 0.0f; }

private:
    // Camera position
    float x_, y_;
    
    // Screen dimensions
    float screenWidth_, screenHeight_;
    
    // World bounds
    bool hasWorldBounds_;
    float worldMinX_, worldMinY_, worldMaxX_, worldMaxY_;
    
    // Target following
    GameObject* target_;
    CameraFollowMode followMode_;
    float smoothness_;  // Higher value = smoother but slower following (1.0 - 10.0)
    
    // Target offset
    float targetOffsetX_, targetOffsetY_;
    
    // Dead zone
    bool deadZoneEnabled_;
    float deadZoneWidth_, deadZoneHeight_;
    
    // Camera shake
    float shakeTimer_;
    float shakeIntensity_;
    float shakeDecay_;
    float shakeOffsetX_, shakeOffsetY_;
    
    // Internal methods
    void updateFollowTarget(float deltaTime);
    void updateCameraShake(float deltaTime);
    void clampToBounds();
    float lerp(float start, float end, float t) const;
    float random(float min, float max) const;
};

#endif // CAMERA_H
